/*
 * @Author: wangzy
 * @Date: 2022-06-28 10:18:00
 * @LastEditors: wangzy
 * @LastEditTime: 2022-06-28 10:39:48
 * @Description: 深拷贝
 */

// 数组 深拷贝

// 1.  Array slice, concat, from

/**
 * 利用 slice() 方法可从已有的数组中返回选定的元素。
 **/
let array = [1, 2, 3, 4, 5]
let newArray = array.slice(0)
newArray[1] = 6
// console.log(array)
// console.log(newArray)
/**
 * concat()可以基于当前数组中的所有项创建一个新数组。
 * 即这个方法会先创建当前数组一个副本，
 * 然后将接收到的参数添加到这个副本的末尾，
 * 最后返回新构建的数组。
 **/
let array2 = [1, 2, 3, 4, 5]
let newArray2 = [].concat(array2)
newArray2[1] = 6
// console.log(array2)
// console.log(newArray2)
/**
 * from() 方法用于通过拥有 length 属性的对象或可迭代的对象来返回一个数组
 **/
let array3 = [1, 2, 3, 4, 5]
let newArray3 = Array.from(array3)
newArray3[1] = 6
console.log(array3)
console.log(newArray3)

/**
 * 实现深拷贝
 **/
function deepClone(target, hash = new WeakMap()) {
  // 额外开辟一个存储空间WeakMap来存储当前对象
  if (target === null) return target // 如果是 null 就不进行拷贝操作
  if (target instanceof Date) return new Date(target) // 处理日期
  if (target instanceof RegExp) return new RegExp(target) // 处理正则
  if (target instanceof HTMLElement) return target // 处理 DOM元素

  if (typeof target !== 'object') return target // 处理原始类型和函数 不需要深拷贝，直接返回

  // 是引用类型的话就要进行深拷贝
  if (hash.get(target)) return hash.get(target) // 当需要拷贝当前对象时，先去存储空间中找，如果有的话直接返回
  const cloneTarget = new target.constructor() // 创建一个新的克隆对象或克隆数组
  hash.set(target, cloneTarget) // 如果存储空间中没有就存进 hash 里

  Reflect.ownKeys(target).forEach((key) => {
    // 引入 Reflect.ownKeys，处理 Symbol 作为键名的情况
    cloneTarget[key] = deepClone(target[key], hash) // 递归拷贝每一层
  })
  return cloneTarget // 返回克隆的对象
}
